package com.food.eat.controller;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.food.eat.enums.YesOrNo;
import com.food.eat.pojo.Carousel;
import com.food.eat.pojo.Category;
import com.food.eat.pojo.vo.CategoryVo;
import com.food.eat.service.CarouselService;
import com.food.eat.service.CategoryService;
import com.food.eat.util.FoodResultJson;
import com.food.eat.util.JsonUtils;
import com.food.eat.util.RedisOperator;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author:RenPu
 * @Date: 2020/7/20 17:11
 * @Version: 1.0
 * @description:
 */

@Api(value = "首页", tags = {"首页展示的相关接口"})
@RestController
@RequestMapping("/index")
public class IndexController extends BaseController {

    @Resource
    private CarouselService carouselService;


    @Resource
    private CategoryService categoryService;


    @Resource
    private RedisOperator redisOperator;

    @ApiOperation(httpMethod = "GET", value = "获取首页轮播图列表", notes = "获取首页轮播图列表")
    @GetMapping("/carousel")
    public FoodResultJson carousel() {

        List<Carousel> carousels = new ArrayList<>();

        //首先去获取redis缓存里去查询
        String carousel = redisOperator.get("carousel");

        //1：判断从redis获取的数据字符串是否为空，为空的话操作数据库，
        // 2：并且把操作数据库的数据缓存到redis，
        // 3：便于下次redis作为用户的缓存屏障，缓解数据库压力，
        // 4：如果redis有相关的数据，将redis的储存的json字符串转化为List进行响应
        if (StringUtils.isBlank(carousel)) {
            carousels = carouselService.queryAllPicture(1);
            redisOperator.set("carousel" + ":" + "007", JsonUtils.objectToJson(carousels));
        } else {
            carousels = JsonUtils.jsonToList(carousel, Carousel.class);
        }


        return FoodResultJson.ok(carousels);
    }


    @ApiOperation(httpMethod = "GET", value = "获取商品分类（一级分类）", notes = "获取商品分类（一级分类）")
    @GetMapping("/cats")
    public FoodResultJson cats() {

        List<Category> categories = new ArrayList<>();

        //首先去获取redis缓存里去查询
        String cats = redisOperator.get("cats");

        //1：判断从redis获取的数据字符串是否为空，为空的话操作数据库，
        // 2：并且把操作数据库的数据缓存到redis，
        // 3：便于下次redis作为用户的缓存屏障，缓解数据库压力，
        // 4：如果redis有相关的数据，将redis的储存的json字符串转化为List进行响应
        if (StringUtils.isBlank(cats)) {
            categories = categoryService.queryByTypeFirstCate();
            redisOperator.set("cats", JsonUtils.objectToJson(categories));
        } else {
            categories = JsonUtils.jsonToList(cats, Category.class);
        }

        return FoodResultJson.ok(categories);
    }


    @ApiOperation(httpMethod = "GET", value = "获取商品子分类", notes = "获取商品子分类")
    @GetMapping("/subCat/{rootCatId}")
    public FoodResultJson subCat(
            @ApiParam(name = "rootCatId", value = "一级分类的id值", required = true)
            @PathVariable Integer rootCatId) {

        List<CategoryVo> categories = new ArrayList<>();

        if (rootCatId == null) {
            return FoodResultJson.errMsg("分类不存在！！！");
        }


        /**
         * 5:缓存穿透的问题，当遇到恶意用户针对redis缓存，数据库不存的id进行反复查询操作，从而给数据库带来宕机的危险，
         *   解决方案：
         *   1:第一将首次进来的恶心请求，查询的任何结果进行存储
         *   2:第二种使用布隆过滤器
         *  布隆过滤器优点：
         *         1:首先布隆过滤器是一种以二进制存在的，所以对项目的空间占有率很低，
         *         2:将每次请求的key进行存储在布隆过滤器的节点，节点存储数据的状态为1，未存储的节点为零，每个节点可以存储多个key
         *         3:每当请求进来，先通过布隆过滤器进行查找当前的key,如果存在在进入缓存或者数据库操作否则直接返回出去
         *  布隆过滤器缺点：
         *          1：布隆过滤存在百分之1的误差，随着布隆过滤器的节点数的增多准确率精度增大，从而代码业务更复杂
         *          2：每个节点可以存储多个key值，再移除单个key值，由于耦合在一起，移除难度加大
         *          3：后期维护难度增加
         */

        /**
         * 6：缓存雪崩问题：当某一个时刻，缓存redis存储的大量key都失效了，此时涌进来大量的访问，直接打在数据库上导致数据库宕机的现象，成为缓存雪崩
         *   解决方案：
         *      1：将key的过期时间设置为永久
         *      2：将每个key的过期时间设置一定的间隔，不要在同一个时刻
         *      3：使用多种缓存机制配合redis来做缓存服务，如mecache
         *      4:使用第三方的redis,如阿里的redis云集群
         *
         *
         */


        //首先去获取redis缓存里去查询
        String subCat = redisOperator.get("subCat:" + rootCatId);

        //1：判断从redis获取的数据字符串是否为空，为空的话操作数据库，
        // 2：并且把操作数据库的数据缓存到redis，
        // 3：便于下次redis作为用户的缓存屏障，缓解数据库压力，
        // 4：如果redis有相关的数据，将redis的储存的json字符串转化为List进行响应
        if (StringUtils.isBlank(subCat)) {
            categories = categoryService.querySubCate(rootCatId);

            //在此解决缓存穿透使用第一种解决方案，首次进来的恶心请求，查询的任何结果进行存储，优点简易，维护起来灵活
            redisOperator.set("subCat:" + rootCatId, JsonUtils.objectToJson(categories));
        } else {
            categories = JsonUtils.jsonToList(subCat, CategoryVo.class);
        }

        return FoodResultJson.ok(categories);
    }


    @ApiOperation(httpMethod = "GET", value = "查询每个一级类别下的最新6条商品数据", notes = "查询每个一级类别下的最新6条商品数据")
    @GetMapping("/sixNewItems/{rootCatId}")
    public FoodResultJson sixNewItems(
            @ApiParam(name = "rootCatId", value = "一级分类的id值", required = true)
            @PathVariable Integer rootCatId) {

        List<CategoryVo> categories = new ArrayList<>();

        if (rootCatId == null) {
            return FoodResultJson.errMsg("分类不存在！！！");
        }


        //首先去获取redis缓存里去查询
        //String sixNewItems = redisOperator.get("sixNewItems:"+rootCatId);
        //categories = JsonUtils.jsonToList(sixNewItems,CategoryVo.class);
        //if(StringUtils.isBlank(sixNewItems)){
        categories = categoryService.getNewSixItems(rootCatId);
        // redisOperator.set("sixNewItems:"+rootCatId,JsonUtils.objectToJson(categories));

        // }


        return FoodResultJson.ok(categories);
    }


}
